package 题目集.线段树or树状数组.线段树;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

/**
 * https://www.luogu.com.cn/problem/P3373
 * 存在加法和乘法操作，
 * 乘法的懒操作会影响加法的懒操作。
 * 假设区间和为a，揽下了一次加b。
 * 当进行乘法时，不光要对区间进行乘法，还要对之前揽下的加操作进行乘法
 */
public class ch04_综合模板_操作间相互影响 {

    static int n, m, mod;
    static Node[] tree;
    static int[] src;

    public static void build(int i, int l, int r) {
        tree[i] = new Node(l, r);
        if (l == r) {
            tree[i].val = src[l];
            return;
        }
        int m = l + r >> 1; //这是实际区间中点
        build(i << 1, l, m);
        build(i << 1 | 1, m + 1, r);
        pull(i);
    }

    public static void add(int i, int l, int r, int v) {
        if (isLazy(i, l, r)) {
            addLazy(i, v);
            return;
        }
        push(i);
        int m = tm(i);
        if (l <= m) {
            add(i << 1, l, r, v);
        }
        if (m < r) {
            add(i << 1 | 1, l, r, v);
        }
        pull(i);
    }

    public static void mul(int i, int l, int r, int v) {
        if (isLazy(i, l, r)) {
            mulLazy(i, v);
            return;
        }
        push(i);
        int m = tm(i);
        if (l <= m) {
            mul(i << 1, l, r, v);
        }
        if (m < r) {
            mul(i << 1 | 1, l, r, v);
        }
        pull(i);
    }

    /**
     * 树的区间中点
     * @param i
     * @return
     */
    private static int tm(int i) {
        return tree[i].l + tree[i].r >> 1;
    }

    public static long query(int i, int l, int r) {
        if (isLazy(i, l, r)) {
            return tree[i].val;
        }
        push(i);
        long res = 0;
        int m = tm(i);
        if (l <= m) {
            res += query(i << 1, l, r);
        }
        if (m < r) {
            res += query(i << 1 | 1, l, r);
        }
        return res % mod;
    }

    public static boolean isLazy(int i, int l, int r) {
        return l <= tree[i].l && tree[i].r <= r;
    }

    public static void push(int i) {
        int l = i << 1;
        int r = l | 1;
        if (tree[i].mul != 1) {
            mulLazy(l, tree[i].mul);
            mulLazy(r, tree[i].mul);
            tree[i].mul = 1;
        }
        if (tree[i].add != 0) {
            addLazy(l, tree[i].add);
            addLazy(r, tree[i].add);
            tree[i].add = 0;
        }
    }

    public static void pull(int i) {
        tree[i].val = tree[i << 1].val + tree[i << 1 | 1].val;
    }

    public static void addLazy(int i, long v) {
        tree[i].val += tree[i].len * v;
        tree[i].add += v;
        mod(i);
    }

    public static void mulLazy(int i, long v) {
        v %= mod;
        tree[i].val *= v;
        tree[i].add *= v;
        tree[i].mul *= v;
        mod(i);
    }

    public static void mod(int i) {
        tree[i].val %= mod;
        tree[i].add %= mod;
        tree[i].mul %= mod;
    }

    public static void main(String[] args) {
        Reader2 sc = new Reader2();
        n = sc.nextInt();
        m = sc.nextInt();
        mod = sc.nextInt();
        int tn = (int) Math.pow(2, Math.ceil(Math.log(n) / Math.log(2)) + 1);
        tree = new Node[tn];
        src = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            src[i]=sc.nextInt();
        }
        build(1,1,n);
        for (int i = 0; i < m; i++) {
            int op=sc.nextInt();
            int l=sc.nextInt();
            int r=sc.nextInt();
            if (op==1){
                mul(1,l,r,sc.nextInt());
            }else if (op==2){
                add(1,l,r,sc.nextInt());
            }else {
                long query = query(1, l, r);
                System.out.println(query);
            }
        }
    }

    static class Node {
        int l, r, len;
        long val, add, mul = 1;

        public Node(int l, int r) {
            this.l = l;
            this.r = r;
            len = r - l + 1;
        }
    }

    static class Reader2 {
        static StreamTokenizer in = new StreamTokenizer(new BufferedInputStream(System.in));
        static PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));

        public Reader2(Object... o) {
        }

        public int nextInt() {
            try {
                in.nextToken();
            } catch (Exception ignored) {
            }
            return (int) in.nval;
        }
    }

}
